#include "SypEngine.h"

#ifdef CHECKMEM
#include "mmgr.h"
#endif

namespace Syp
{



	Camera* Camera::createCamera()
	{
		return (new Camera());

	}

	void Camera::destroyCamera(Camera* cam)
	{
		delete cam;
	}

	bool Camera::isAnimated()
	{
		return animate;
	}

	void Camera::setAnimation(bool enabled)
	{
		animate = enabled;
	}

	///Returns the camera's FOV.
	float Camera::getFOV()
	{
		return fov;
	}
	///Returns the camera's aspect
	float Camera::getAspect()
	{
		return aspect;
	}
	///Returns the Camera's nearClip value
	float Camera::getNearClip()
	{
		return nearClip;
	}
	///Returns the Camera's farClip value
	float Camera::getFarClip()
	{
		return farClip;
	}

	//Returns the Camera's nearClip value
	void Camera::setNearClip(float near)
	{
		nearClip = near;
	}
	///Returns the Camera's farClip value
	void Camera::setFarClip(float far)
	{
		farClip = far;
	}
	///Returns the camera's animation playback speed
	float Camera::getAnimSpeed()
	{
		return speed;
	}

	void Camera::update()
	{
		assert(animate && "Animate appears to be set to false, Execution should'nt have reached here in the first place. Please report this as a bug.");
		//Get time elapsed
		double timeElapsed = SypEngine::getSypEngine().getElapsedTime();
		//update 
		//(Mesh's relative time in frames)
		AnimTime += static_cast<float>(timeElapsed * speed);

		//If animation is over, restart it
		//Possibly add other modes in future
		if(AnimTime > AnimLength)
		{
			//SUppose our time is 306 and animlength is 100, our outstanding is 206 frames. 
			// 306 / 100 is 3
			// 306 - (3* 100) = 6

			AnimTime = AnimTime - ((AnimTime / AnimLength) * AnimLength);				
		}

		std::vector<KeyFrame>::iterator LowerKey;
		std::vector<KeyFrame>::iterator UpperKey;
		float interpolation = 0.0f;//float defining how much to interpolate by

		KeyFrame tk;
		tk.time = AnimTime;
		////////////////////////////Find the correct KeyFrame////////////////////
		//Following code finds the 2 keyframes which surround AnimTime


		//find the 2 keys surrounding this time								
		LowerKey = std::upper_bound( KFrame.begin(), 
			KFrame.end(),
			tk);
		UpperKey = LowerKey--;
		//We now have both our keyframes

		double timeDiff = UpperKey->time - LowerKey->time;
		//Interpolation between the 2 frames
		interpolation = static_cast<float> ( (AnimTime - LowerKey->time) / timeDiff);
		//Make some noise if interpolation is not less then 1.0f
		assert(interpolation <= 1.0f && "Interpolation has gone beyond 1.0f for Camera. This should not be happening in the first place. Please report this as a bug");
		//Now to interpolate them
		Quat resultCam;
		Point3 resultCamPos;
		Math::InterpolateQuat(LowerKey->Rot,UpperKey->Rot,resultCam, interpolation);
		Math::InterpolatePoint3(LowerKey->Pos,UpperKey->Pos,resultCamPos,interpolation);	

		setOrientation(resultCam.x,resultCam.y,resultCam.z,resultCam.w);
		setPosition(resultCamPos.x,resultCamPos.y,resultCamPos.z);

		//That's it

	}

	void Camera::loadCameraFromFile(String filename)
	{
		String temp;
		InputStream fin;
		fin.open(filename.c_str());
		//CameraName
		fin>>temp;
		//Read in name
		fin>>name;
		//Read in Pos
		fin>>temp;
		//pos
		float x,y,z,w;
		fin>>x;
		fin>>y;
		fin>>z;
		setPosition(x,y,z);
		//Read in Rot
		fin>>temp;
		//Rot
		fin>>x;
		fin>>y;
		fin>>z;
		fin>>w;
		setOrientation(x,y,z,w);
		//	orientation = orientation.convertToQuat();
		//FOV
		fin>>temp;
		fin>>fov;
		//Near
		fin>>temp;
		fin>>nearClip;
		//Far
		fin>>temp;
		fin>>farClip;
		//read in Time or NotAnimated
		fin>>temp;
		while(temp == "Time")
		{
			KeyFrame Tkey;

			fin>>Tkey.time;
			//4800 ticks is 1 sec
			Tkey.time /= 4800.0f;
			//We just store the time, the last time will be the last keyframe meaning animlength
			AnimLength = Tkey.time;

			fin>>temp;
			fin>>Tkey.Pos.x;
			fin>>Tkey.Pos.y;
			fin>>Tkey.Pos.z;

			fin>>temp;
			fin>>Tkey.Rot.x;
			fin>>Tkey.Rot.y;
			fin>>Tkey.Rot.z;
			fin>>Tkey.Rot.w;		

			//Tkey.Rot = Tkey.Rot.convertToQuat();

			Tkey.Rot.Normalize();

			KFrame.push_back(Tkey);

			fin>>temp;

		}

		fin.close();


	}

}
